package com.tangji.signaltower.resources;

import com.fqgj.common.utils.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author poyangchen
 * @Create 2017-03-31 下午8:56
 * @Description
 */
public class HttpUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtil.class);
    private static final String DEFAULT_CHARSET = "UTF-8";

    private static RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(10000)
            .setConnectTimeout(10000)
            .setSocketTimeout(60000).build();

    public static String postPage(String url, Map<String, String> parameters) {
        return postPage(url, parameters, null, DEFAULT_CHARSET);

    }

    public static String postPage(String url, Map<String, String> parameters, String charset) {
        return postPage(url, parameters, null, charset);

    }

    public static String getPage(String url, Map<String, String> parameters) {
        return getPage(url, parameters, null, DEFAULT_CHARSET);

    }

    public static String getPage(String url) {
        return getPage(url, null, null, DEFAULT_CHARSET);

    }

    public static String getPage(String url, String charset) {
        return getPage(url, null, null, charset);

    }

    public static String getPage(String url, Map<String, String> parameters, String charset) {
        return getPage(url, parameters, null, charset);

    }

    public static String postPage(String url, Map<String, String> parameters, Map<String, String> headers) {
        return postPage(url, parameters, headers, DEFAULT_CHARSET);

    }

    public static String getPage(String url, Map<String, String> parameters, Map<String, String> headers) {

        return getPage(url, parameters, headers, DEFAULT_CHARSET);
    }

    public static String postPage(String url, Map<String, String> parameters, Map<String, String> headers, String charset) {
        String result = "";

        CloseableHttpClient client = HttpClients.createDefault();

        HttpPost httppost = new HttpPost(url);

        if (CollectionUtils.isNotEmpty(headers)) {
            pushParamsToHeader(httppost, headers);
        }

        List<NameValuePair> list = pushParamsToNameValuePair(parameters);

        CloseableHttpResponse response = null;

        try {
            // 构建url加密实体，并以utf-8方式进行加密；
            httppost.setEntity(new UrlEncodedFormEntity(list, charset));
            response = client.execute(httppost);

//            if (response.getStatusLine().getStatusCode() == 200) {
            result = EntityUtils.toString(response.getEntity(), charset);
//            }
        } catch (Exception e) {
            LOGGER.error("post request error,url:" + url + ",parameters:" + parameters, e);
        } finally {
            close(response);
            close(client);
        }
        return result;
    }

    public static String putPage(String pageUrl, Map<String, String> headers) {

        String result = "";
        CloseableHttpClient client = HttpClients.createDefault();

        HttpPut httpPut = new HttpPut(pageUrl);

        if (CollectionUtils.isNotEmpty(headers)) {
            pushParamsToHeader(httpPut, headers);
        }

        CloseableHttpResponse response = null;
        try {
            response = client.execute(httpPut);
//            if (response.getStatusLine().getStatusCode() == 200) {
            result = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
//            }
        } catch (Exception e) {
            LOGGER.error("put request error,url:" + pageUrl, e);
        } finally {
            close(response);
            close(client);
        }
        return result;
    }

    public static String getPage(String pageUrl, Map<String, String> parameters, Map<String, String> headers, String charset) {

        String result = "";
        CloseableHttpClient client = HttpClients.createDefault();

        pageUrl = joinGetUrl(pageUrl, parameters);
        HttpGet httpGet = new HttpGet(pageUrl);

        if (CollectionUtils.isNotEmpty(headers)) {
            pushParamsToHeader(httpGet, headers);
        }

        CloseableHttpResponse response = null;
        try {
            response = client.execute(httpGet);
//            if (response.getStatusLine().getStatusCode() == 200) {
            result = EntityUtils.toString(response.getEntity(), charset);
//            }
        } catch (Exception e) {
            LOGGER.error("get request error,url:" + pageUrl, e);
        } finally {
            close(response);
            close(client);
        }
        return result;
    }

    public static void close(CloseableHttpResponse response) {
        if (response != null) {
            try {
                HttpEntity httpEntity = response.getEntity();
                if (httpEntity != null) {
                    InputStream in = httpEntity.getContent();
                    if (in != null) {
                        in.close();
                    }
                }
            } catch (Exception ex) {
                // ignore
            }

            try {
                response.close();
            } catch (Exception ex) {
                // ignore
            }
        }
    }

    public static String postPageBody(String pageUrl, Map<String, String> headers, String requestBody) {
        if (pageUrl.startsWith("https")) {
            return postPageBodyByHttps(pageUrl, headers, requestBody);
        }

        String result = "";

        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(pageUrl);
        httpPost.setConfig(requestConfig);

        if (CollectionUtils.isNotEmpty(headers)) {
            pushParamsToHeader(httpPost, headers);
        }
        CloseableHttpResponse response = null;
        try {

            httpPost.setEntity(new StringEntity(requestBody, DEFAULT_CHARSET));
            response = client.execute(httpPost);

            result = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
        } catch (Exception e) {
            LOGGER.error("post request error,url: {}, params: {}.", pageUrl, requestBody, e);
        } finally {
            close(response);
            close(client);
        }

        return result;
    }

    public static void close(CloseableHttpClient httpClient) {
        if (httpClient != null) {
            try {
                httpClient.close();
            } catch (Exception ex) {
                // ignored
            }
        }
    }

    public static List<NameValuePair> pushParamsToNameValuePair(Map<String, String> parameters) {
        // 构建请求参数
        List<NameValuePair> list = new ArrayList<NameValuePair>();

        //添加参数
        if (CollectionUtils.isNotEmpty(parameters)) {
            Iterator<Map.Entry<String, String>> it = parameters.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, String> entry = it.next();
                String key = entry.getKey();
                String value = entry.getValue();
                list.add(new BasicNameValuePair(key, value));
            }

        }
        return list;
    }

    public static String joinGetUrl(String pageUrl, Map<String, String> parameters) {

        if (CollectionUtils.isEmpty(parameters)) {
            return pageUrl;
        }
        // create post request
        StringBuilder params = new StringBuilder();
        int i = 1;
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            if (i == parameters.size()) {
                params.append(entry.getKey() + "=" + entry.getValue());
            } else {
                params.append(entry.getKey() + "=" + entry.getValue() + "&");
            }
            i++;
        }

        return pageUrl + "?" + params;
    }

    public static void pushParamsToHeader(HttpGet httpGet, Map<String, String> headers) {
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            httpGet.addHeader(entry.getKey(), entry.getValue());
        }
    }

    public static void pushParamsToHeader(HttpPut httpPut, Map<String, String> headers) {
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            httpPut.addHeader(entry.getKey(), entry.getValue());
        }
    }

    public static void pushParamsToHeader(HttpPost httpPost, Map<String, String> headers) {
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            httpPost.addHeader(entry.getKey(), entry.getValue());
        }
    }

    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (StringUtils.isNotEmpty(ip) && ip.indexOf(",") != -1) {
            String[] temp = ip.split(",");
            ip = temp[0];
        }
        return ip;
    }

    public static Map<String, String> getParameters(Map<String, String[]> params) {
        Map<String, String> paramsMap = new HashMap<String, String>();
        for (Map.Entry<String, String[]> entry : params.entrySet()) {
            String value = entry.getValue() == null || entry.getValue().length == 0 ? null : entry.getValue()[0];
            paramsMap.put(entry.getKey(), value);
        }

        return paramsMap;
    }

    /**
     * https方式发包
     *
     * @param url
     * @param headers
     * @param requestBody
     * @return
     */
    public static String postPageBodyByHttps(String url, Map<String, String> headers, String requestBody) {
//        HttpHost proxy = new HttpHost("172.90.15.153", 8888);
        RequestConfig config = RequestConfig.custom()
                .setConnectionRequestTimeout(10000)
                .setConnectTimeout(30000)
                .setSocketTimeout(60000)
//                .setProxy(proxy)
                .build();
        SSLContext sslcontext = null;
        try {
            sslcontext = createIgnoreVerifySSL();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext, hostnameVerifier);
        HttpClientBuilder builder = HttpClientBuilder.create()
                .setDefaultRequestConfig(config)
                .setRetryHandler(new StandardHttpRequestRetryHandler())
                //大多数HTTP连接都被认为是持久的。但是，为了节省服务器资源，连接很少永远保持打开，许多服务器的默认连接超时相当短，例如Apache httpd 2.2及更高版本的5秒。
                //Http客户端池中设置保持未使用连接打开的最长时间
                .setConnectionTimeToLive(3000, TimeUnit.MILLISECONDS)
                //忽略证书
                .setSSLSocketFactory(socketFactory);
        CloseableHttpClient closeableHttpClient = builder.build();

        HttpPost httpPost = new HttpPost(url);

        if (CollectionUtils.isNotEmpty(headers)) {
            pushParamsToHeader(httpPost, headers);
        }

        String result = "";
        CloseableHttpResponse response = null;
        try {

            httpPost.setEntity(new StringEntity(requestBody, "UTF-8"));
            response = closeableHttpClient.execute(httpPost);

            result = EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            LOGGER.error("post request error,url: {}, params: {}.", url, requestBody, e);
        } finally {
            close(response);
            close(closeableHttpClient);
        }
        return result;
    }

    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("TLSv1.2");

        // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);
        return sc;
    }

    private static X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
        @Override
        public void verify(String host, SSLSocket ssl) throws IOException {
        }

        @Override
        public void verify(String host, X509Certificate cert)
                throws SSLException {
        }

        @Override
        public void verify(String host, String[] cns, String[] subjectAlts)
                throws SSLException {
        }

        @Override
        public boolean verify(String arg0, SSLSession arg1) {
            return true;
        }
    };

}
